/*
 * Copyright 2019 xiaomaoguai.com All right reserved. This software is the
 * confidential and proprietary information of xiaomaoguai.com ("Confidential
 * Information"). You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license agreement you entered
 * into with xiaomaoguai.com.
 */

package com.xiaomaoguai.core.next.hsf.http;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
import com.google.common.reflect.Reflection;

/**
 * HSF接口FactoryBean，用于注册HSF HTTP请求代理，返回HSF接口的代理对象
 *
 * @param <T> 范型
 * @author chenyao
 * @since 2016年8月17日 下午3:48:02
 */
public class HsfHttpRequestFactoryBean<T> implements InitializingBean, FactoryBean<T> {
    private Object              proxyInstance;
    private final Class<T>      hsfInterface;
    private HsfHttpRequestProxy hsfHttpRequestProxy;
    private RestTemplate        restTemplate;
    private String              serviceVersion;
    private String              serverUrl;
    private ObjectDeserializer  responseBodyDeserializer;

    /**
     * 创建HSF接口FactoryBean，是通过 "HSF HTTP协议" 调用的，这是 "HSF 容器" 原生支持的。
     * <p>
     * 已知问题：
     * <ul>
     * <li>大量请求，会遇到超时问题
     * <li>请求参数中的字符内容有 &amp; 符号，就会解析失败
     * </ul>
     *
     * @param hsfInterface 代理的 HSF 接口 class 类
     */
    public HsfHttpRequestFactoryBean(Class<T> hsfInterface) {
        this.hsfInterface = hsfInterface;
    }

    /**
     * 代理对象
     *
     * @return 代理对象
     */
    @SuppressWarnings("unchecked")
    @Override
    public T getObject() {
        return (T) this.proxyInstance;
    }

    @Override
    public Class<?> getObjectType() {
        return this.hsfInterface;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    /**
     * 注册HSF HTTP请求代理
     */
    @Override
    public void afterPropertiesSet() {
        if (this.restTemplate == null) {
            this.restTemplate = new RestTemplate();
        }
        if (this.hsfHttpRequestProxy == null) {
            this.hsfHttpRequestProxy = new HsfHttpRequestProxy(restTemplate, serviceVersion, serverUrl,
                    this.responseBodyDeserializer);
        }
        this.proxyInstance = Reflection.newProxy(this.hsfInterface, hsfHttpRequestProxy);
    }

    /**
     * HSF接口使用HTTP请求代理类，如果没有设置此值，下面这三个字段必须设置：
     * <ul>
     * <li>{@link #setRestTemplate(RestTemplate)}（可选）
     * <li>{@link #setServiceVersion(String)}
     * <li>{@link #setServerUrl(String)}
     * </ul>
     *
     * @param hsfHttpRequestProxy HSF接口使用HTTP请求代理类
     * @return {@code HsfHttpRequestFactoryBean}
     */
    public HsfHttpRequestFactoryBean setHsfHttpRequestProxy(HsfHttpRequestProxy hsfHttpRequestProxy) {
        this.hsfHttpRequestProxy = hsfHttpRequestProxy;
        return this;
    }

    /**
     * 访问Rest服务的客户端，建议此字段设置成具有连接池的单一对象
     *
     * @param restTemplate 访问Rest服务的客户端
     * @return {@code HsfHttpRequestFactoryBean}
     * @see #setHsfHttpRequestProxy(HsfHttpRequestProxy)
     */
    public HsfHttpRequestFactoryBean setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
        return this;
    }

    /**
     * HSF接口的服务版本
     *
     * @param serviceVersion HSF接口的服务版本
     * @return {@code HsfHttpRequestFactoryBean}
     * @see #setHsfHttpRequestProxy(HsfHttpRequestProxy)
     */
    public HsfHttpRequestFactoryBean setServiceVersion(String serviceVersion) {
        this.serviceVersion = serviceVersion;
        return this;
    }

    /**
     * HSF服务的HTTP IP地址，举例：http://ip:port
     *
     * @param serverUrl HSF服务的HTTP IP地址
     * @return {@code HsfHttpRequestFactoryBean}
     * @see #setHsfHttpRequestProxy(HsfHttpRequestProxy)
     */
    public HsfHttpRequestFactoryBean setServerUrl(String serverUrl) {
        this.serverUrl = serverUrl;
        return this;
    }

    /**
     * 使用自定义反序列化类来操作：HSF接口返回的值，解决某些泛型类型、特殊的需求（可选）
     *
     * @param responseBodyDeserializer 使用自定义反序列化类
     * @see #setHsfHttpRequestProxy(HsfHttpRequestProxy)
     */
    public void setResponseBodyDeserializer(ObjectDeserializer responseBodyDeserializer) {
        this.responseBodyDeserializer = responseBodyDeserializer;
    }
}
